/*	
*	File: udp-packet.h
*	Date: 2011/11/08
*	User: Ronmaru
*	Desctiption: udp packet class
*/

#include "pcraft-tool.h"

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <string>
#include <istream>
#include <iostream>
#include <ostream>

//using boost::asio::ip::udp;
using boost::asio::deadline_timer;
namespace posix_time = boost::posix_time;

class UDPpacket
{
public:
  UDPpacket(boost::asio::io_service& io_service, UDPheader header, UDPpseudoheader pseudo_header,
    const std::string &body)
    : udp_resolver_(io_service), udp_socket_(io_service, raw::v4()),
    udp_header_(header), udp_pseudo_header_(pseudo_header), udp_body_(body), encapsulate_ip_(1)
  {
    raw::resolver::query query(raw::v4(), pseudo_header.GetDestinationAddress().to_string(), "");
    udp_destination_ = *udp_resolver_.resolve(query);

    udp_socket_.connect(udp_destination_);
  }

  UDPpacket(boost::asio::io_service& io_service, IPV4header ipv4_header, 
    UDPheader icmp_header, UDPpseudoheader pseudo_header, const std::string &body)
    : udp_resolver_(io_service), udp_socket_(io_service, raw::v4()), udp_pseudo_header_(pseudo_header), 
    udp_header_(icmp_header), ipv4_header_(ipv4_header), udp_body_(body), encapsulate_ip_(0)
  {
    raw::resolver::query query(raw::v4(), ipv4_header.GetDestinationAddress().to_string(), "");
    udp_destination_ = *udp_resolver_.resolve(query);

    udp_socket_.connect(udp_destination_);
    const ip_hdrincl opt_ip_hdrincl(1);
    udp_socket_.set_option(opt_ip_hdrincl);
  }

  void send()
  {
    boost::asio::streambuf request_buffer;
    std::ostream os(&request_buffer);
    ComputeChecksum(udp_header_, udp_pseudo_header_, udp_body_.begin(), udp_body_.end());
    if (encapsulate_ip_) {
      os << udp_header_ << udp_body_;
    } else {
      os << ipv4_header_ << udp_header_ << udp_body_;
    }

    udp_socket_.send(request_buffer.data());
  }

  int encapsulate_ip_;
  raw::resolver udp_resolver_;
  raw::endpoint udp_destination_;
  raw::socket udp_socket_;
  std::string udp_body_;

  UDPheader udp_header_;
  UDPpseudoheader udp_pseudo_header_;
  IPV4header ipv4_header_;
};